Þ¥bonds€¬cell_resultsÞ0Ù$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2Цqueued¤logs�§running¦output†¤bodyÙ¼

That's all you need! Pluto will synchronise the value of x with the latest value of the HTML input. Try moving the slider! 👆

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0_p°persist_js_state·has_pluto_hook_features§cell_idÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2¹depends_on_disabled_cells§runtimeιµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$beb9a2bd-cbf5-4679-8403-fc249191f65eЦqueued¤logs�§running¦output†¤bodyÚ 
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0¼4°persist_js_state·has_pluto_hook_features§cell_idÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e¹depends_on_disabled_cells§runtimeεpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557dbЦqueued¤logs�§running¦output†¤bodyÚß

Tip

In this example, we immediately call update() and trigger an input event with the initial value. If we didn't do that, the value of counter would be nothing until the first interaction. Whether that's appropriate, depends on the interaction you want. In this case, it made sense that the counter should start at 0!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0ýr°persist_js_state·has_pluto_hook_features§cell_idÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db¹depends_on_disabled_cells§runtimeÎU³µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01fЦqueued¤logs�§running¦output†¤bodyÚt

The script is now keeping track of clicks, but it's not sending that value anywhere.

We need to:

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0£¾°persist_js_state·has_pluto_hook_features§cell_idÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f¹depends_on_disabled_cells§runtime΂5µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$33b5374c-91d1-4122-82c5-f793d063ffdcЦqueued¤logs�§running¦output†¤bodyÙ@¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3¿ N°persist_js_state·has_pluto_hook_features§cell_idÙ$33b5374c-91d1-4122-82c5-f793d063ffdc¹depends_on_disabled_cells§runtimeÎ Îȵpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$4a235d55-a80f-43c7-8f13-759976d88656Цqueued¤logs�§running¦output†¤bodyÙA¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3¾á°persist_js_state·has_pluto_hook_features§cell_idÙ$4a235d55-a80f-43c7-8f13-759976d88656¹depends_on_disabled_cells§runtimeΠɘµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$788c0b9b-238f-4402-b24f-52648103512eЦqueued¤logs�§running¦output†¤bodyÙð

If you're looking for something more sophisticated than simple string interpolation, check out the HyperTextLiteral package!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0Ÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$788c0b9b-238f-4402-b24f-52648103512e¹depends_on_disabled_cells§runtimeÎÊRµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2969d603-9b6c-403e-abdc-af078c2e53f1Цqueued¤logs�§running¦output†¤bodyÙw
Let's make something interactive here!
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0:—°persist_js_state·has_pluto_hook_features§cell_idÙ$2969d603-9b6c-403e-abdc-af078c2e53f1¹depends_on_disabled_cells§runtimeÎÑyµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6eЦqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ­†3ù6ưpersist_js_state·has_pluto_hook_features§cell_idÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e¹depends_on_disabled_cells§runtimeͰµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$73c8532e-09a6-429b-b8f6-530c00d92428Цqueued¤logs�§running¦output†¤bodyÚø

Interactivity with HTML

Pluto notebooks can use the @bind macro for interactive inputs. Neat!

If you're completely new to coding anything interactive in a web browser, the easiest way to get started is with the PlutoUI package in Julia. (Check out the PlutoUI featured notebook if you'd like to learn more about that!)

If you have some experience with HTML, or if you would like to learn how to make your own interactive elements, this notebook is for you! We'll cover the basics of using @bind with HTML elements. Let's get started!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0s°persist_js_state·has_pluto_hook_features§cell_idÙ$73c8532e-09a6-429b-b8f6-530c00d92428¹depends_on_disabled_cells§runtimeÎÓ5µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$1ebba747-47f8-4ecd-809d-359e6d803ddcЦqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassignee¡y²last_run_timestampËAÚ­†3¾²Ì°persist_js_state·has_pluto_hook_features§cell_idÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc¹depends_on_disabled_cells§runtimeÍ/¨µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$582769e6-7eb1-11ea-077d-d9b4a3226aacЦqueued¤logs�§running¦output†¤bodyÚ

Behind the scenes

If you're curious to learn a bit more about how this all works, keep reading!

The output value

As we've mentioned, bound values are just the latest value of the input element, rather than some kind of observable.

The update mechanism is lossy and lazy, which means that it will skip values if your code is still running - and only send the latest value when your code is ready again. This is important when changing a slider from 0 to 100, for example. If it would send all intermediate values, it might take a while for your code to process everything, causing a noticeable lag.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0^ê°persist_js_state·has_pluto_hook_features§cell_idÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac¹depends_on_disabled_cells§runtimeÎÂýµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$de1b9643-66fa-4918-9a93-0f340c8548baЦqueued¤logs�§running¦output†¤bodyÙ²

Now we can use the script to handle whatever interaction we want. For a simple element, let's add a button and count the number of clicks.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0X*°persist_js_state·has_pluto_hook_features§cell_idÙ$de1b9643-66fa-4918-9a93-0f340c8548ba¹depends_on_disabled_cells§runtimeÎ6 µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$82c7b1ea-08c0-495f-baba-37e5497abde2Цqueued¤logs�§running¦output†¤bodyÙC

It's as simple as that!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0Ýv°persist_js_state·has_pluto_hook_features§cell_idÙ$82c7b1ea-08c0-495f-baba-37e5497abde2¹depends_on_disabled_cells§runtimeÎÄrµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$cb65a4ee-02e5-4779-8728-b994d8af645dЦqueued¤logs�§running¦output†¤body§Missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ­†3»Š3°persist_js_state·has_pluto_hook_features§cell_idÙ$cb65a4ee-02e5-4779-8728-b994d8af645d¹depends_on_disabled_cells§runtimeÍ#xµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013Цqueued¤logs�§running¦output†¤bodyÚ
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3ùŒ¹°persist_js_state·has_pluto_hook_features§cell_idÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013¹depends_on_disabled_cells§runtimeÎ 7Àµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611dЦqueued¤logs�§running¦output†¤bodyÙA¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3¿â†°persist_js_state·has_pluto_hook_features§cell_idÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d¹depends_on_disabled_cells§runtimeÎ}„µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$ced18648-7eb2-11ea-2052-07795685f0daЦqueued¤logs�§running¦output†¤bodyÚd

JavaScript?

Yes! We are using Generator.input from observablehq/stdlib to create a JS Generator (kind of like an Observable) that listens to onchange, onclick or oninput events, depending on the element type.

This makes it super easy to create nice HTML/JS-based interaction elements - a package creator simply has to write a show method for MIME type text/html that creates a DOM object that triggers the input event. In other words, Pluto's @bind will behave exactly like viewof in observablehq.

If you want to learn more about using Javascript in Pluto, check out the JavaScript sample notebook!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0â‚°persist_js_state·has_pluto_hook_features§cell_idÙ$ced18648-7eb2-11ea-2052-07795685f0da¹depends_on_disabled_cells§runtimeÎ ùXµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54dЦqueued¤logs�§running¦output†¤bodyÙœ

Keep in mind that changing the value of limit will re-evaluate the slider cell, so it will reset the value.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0?§°persist_js_state·has_pluto_hook_features§cell_idÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d¹depends_on_disabled_cells§runtimeÎx›µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$bd24d02c-7eac-11ea-14ab-95021678e71eЦqueued¤logs�§running¦output†¤bodyÙ@¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3JBF°persist_js_state·has_pluto_hook_features§cell_idÙ$bd24d02c-7eac-11ea-14ab-95021678e71e¹depends_on_disabled_cells§runtimeÎ0âµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$0a7018ca-2afe-42b1-850f-a649e570709fЦqueued¤logs�§running¦output†¤bodyÙ–

A neat aspect of this @bind macro is that on the Julia side, x is just a normal integer:

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0€å°persist_js_state·has_pluto_hook_features§cell_idÙ$0a7018ca-2afe-42b1-850f-a649e570709f¹depends_on_disabled_cells§runtimeÎ%+µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955Цqueued¤logs�§running¦output†¤bodyÙõ

Input types

You can use binds with anything that fires an input event. For example:

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0Ãç°persist_js_state·has_pluto_hook_features§cell_idÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955¹depends_on_disabled_cells§runtimeΛµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365aЦqueued¤logs�§running¦output†¤bodyÙ?¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3À€°persist_js_state·has_pluto_hook_features§cell_idÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a¹depends_on_disabled_cells§runtimeÎ ½µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51Цqueued¤logs�§running¦output†¤bodyÚŒ

Tip

Interpolating values in Javascript is neat, but remember that we are just taking the string representation of the variable and pasting it in the javascript code. For some complex data types like dates, you will need to do a bit of conversion to turn them into proper javascript expressions.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0~¦°persist_js_state·has_pluto_hook_features§cell_idÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51¹depends_on_disabled_cells§runtimeÎâµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$c50a5e52-7c95-445c-86ee-c60104a39dbdЦqueued¤logs�§running¦output†¤bodyÚÐ

Using Julia values in HTML

We've seen how you can pass on values from an interactive HTML element on to Julia, but for proper interaction, we also want to do it the other way around!

The most basic way to do this is string interpolation. In this example, you can change the value of limit in the code to affect the maximum value of the slider. Try it out!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0!ÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd¹depends_on_disabled_cells§runtimeÎܵpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Цqueued¤logs�§running¦output†¤bodyÙm¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†4¶°persist_js_state·has_pluto_hook_features§cell_idÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122¹depends_on_disabled_cells§runtimeÎ whµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881Цqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ­†3ís°persist_js_state·has_pluto_hook_features§cell_idÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881¹depends_on_disabled_cells§runtimeÍ$µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$e3eb31ae-c512-426f-915c-01144edbc90dЦqueued¤logs�§running¦output†¤bodyÚÔ
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3ì~9°persist_js_state·has_pluto_hook_features§cell_idÙ$e3eb31ae-c512-426f-915c-01144edbc90d¹depends_on_disabled_cells§runtimeÎ&¡Ëµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2cefd0de-db13-49c1-abeb-097792ef46f6Цqueued¤logs�§running¦output†¤bodyÙÈ

For something even fancier, you can also interpolate value in Javascript. For example, here I have adapted my counter so it won't count past limit:

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0\£°persist_js_state·has_pluto_hook_features§cell_idÙ$2cefd0de-db13-49c1-abeb-097792ef46f6¹depends_on_disabled_cells§runtimeÎ µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$3297233b-9567-4d5e-8138-93ebe20fed48Цqueued¤logs�§running¦output†¤bodyƒ¨elements’’’§missingªtext/plain’’§missingªtext/plain¤type¥Tuple¨objectid°ffffffff944f3bac¤mimeÙ!application/vnd.pluto.tree+object¬rootassigneeÀ²last_run_timestampËAÚ­†4Ñ‘°persist_js_state·has_pluto_hook_features§cell_idÙ$3297233b-9567-4d5e-8138-93ebe20fed48¹depends_on_disabled_cells§runtimeÍ\0µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$cb1fd532-7eac-11ea-307c-ab16b1977819Цqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ­†3v»,°persist_js_state·has_pluto_hook_features§cell_idÙ$cb1fd532-7eac-11ea-307c-ab16b1977819¹depends_on_disabled_cells§runtimeÍHXµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$9985a640-c1d3-48dc-b00b-d7500085a37bЦqueued¤logs�§running¦output†¤bodyÙŠ ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3¿‰ã°persist_js_state·has_pluto_hook_features§cell_idÙ$9985a640-c1d3-48dc-b00b-d7500085a37b¹depends_on_disabled_cells§runtimeÎ ã_µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$816ea402-7eae-11ea-2134-fb595cca3068Цqueued¤logs�§running¦output†¤bodyÚ

Not an observable, callback, or something else that you need to wrap your head around. You can use x like you would any other number, and Pluto's reactivity means anything depending on x will be updated with it. 🚀

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0ŸQ°persist_js_state·has_pluto_hook_features§cell_idÙ$816ea402-7eae-11ea-2134-fb595cca3068¹depends_on_disabled_cells§runtimeÎQеpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2Цqueued¤logs�§running¦output†¤bodyÙD¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3¿aF°persist_js_state·has_pluto_hook_features§cell_idÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2¹depends_on_disabled_cells§runtimeÎ '—µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecfЦqueued¤logs�§running¦output†¤bodyÙ‚

Okay, now we can use this HTML snippet with a @bind macro and see the result!

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0Ú°persist_js_state·has_pluto_hook_features§cell_idÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf¹depends_on_disabled_cells§runtimeÎÙµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$1a338f77-d8f3-4569-a2d5-c174368a4761Цqueued¤logs�§running¦output†¤bodyÙZ ¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†3ø«z°persist_js_state·has_pluto_hook_features§cell_idÙ$1a338f77-d8f3-4569-a2d5-c174368a4761¹depends_on_disabled_cells§runtimeÎ ¯µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$c5a5e243-39d6-43d9-8de7-887661ba99cdЦqueued¤logs�§running¦output†¤bodyÙm¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†4۰persist_js_state·has_pluto_hook_features§cell_idÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd¹depends_on_disabled_cells§runtimeÎ ÅØµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164bЦqueued¤logs�§running¦output†¤bodyÚf

This is is how the PlutoUI package works - it defines HTML literals - sometimes with their own scripts.

If you've written some cool HTML inputs and you want to share them with others, you can also make a UI package! Just publish those definitions as a Julia package and you're done! ✨

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0(ž°persist_js_state·has_pluto_hook_features§cell_idÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b¹depends_on_disabled_cells§runtimeÎ ˆÈµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfaЦqueued¤logs�§running¦output†¤bodyÙô

Reusing elements

Once you've written some neat interactive element, you may want to use it a few times in notebook. The easiest way is to put the HTML literal in a variable.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0¿Y°persist_js_state·has_pluto_hook_features§cell_idÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa¹depends_on_disabled_cells§runtime΢óµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$8f829274-7eb1-11ea-3888-13c00b3ba70fЦqueued¤logs�§running¦output†¤bodyÚB

What does the macro do?

The @bind macro does not actually contain the interactivity mechanism, this is built into Pluto itself. Still, it does two things: it assigns a default value to the variable (missing in most cases), and it wraps the second argument in a PlutoRunner.Bond object.

For example, expanding the @bind macro turns this expression:

@bind x Slider(5:15)

into (simplified):

begin
    local el = Slider(5:15)
    global x = AbstractPlutoDingetjes.intial_value(el)
    PlutoRunner.create_bond(el, :x)
end

We see that the macro creates a variable x, which is given the value AbstractPlutoDingetjes.intial_value(el). This function returns missing by default, unless a method was implemented for your widget type. For example, PlutoUI has a Slider type, and it defines a method for intial_value(slider::Slider) that returns the default number.

Declaring a default value using AbstractPlutoDingetjes is not necessary, as shown by the earlier examples in this notebook, but the default value will be used for x if the notebook.jl file is run as a plain julia file, without Pluto's interactivity.

You don't need to worry about this if you are just getting started with Pluto and interactive elements, but more advanced users should take a look at AbstractPlutoDingetjes.jl.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0¢Œ°persist_js_state·has_pluto_hook_features§cell_idÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f¹depends_on_disabled_cells§runtimeÎ f µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcfЦqueued¤logs�§running¦output†¤bodyƒ¨elements–’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain’’§missingªtext/plain¤type¥Tuple¨objectid°ffffffff2bb69edc¤mimeÙ!application/vnd.pluto.tree+object¬rootassigneeÀ²last_run_timestampËAÚ­†3ì!�°persist_js_state·has_pluto_hook_features§cell_idÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf¹depends_on_disabled_cells§runtimeÍ8µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403Цqueued¤logs�§running¦output†¤bodyÚ

Scripting inputs with Javascript

You can also use Javascript to write more complicated inputs.

To get started with this, add a <script> tag to your cell. The easiest setup is to make the script a child of the cell's root element. Then you can use currentScript.parentElement to select the script's parent element.

For instance, here a HTML snippet with a script added to it.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0!Ÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403¹depends_on_disabled_cells§runtimeÎ�tµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$f1f53700-099b-4653-93f1-6b39acdc4c58Цqueued¤logs�§running¦output†¤bodyÙì
¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0p °persist_js_state·has_pluto_hook_features§cell_idÙ$f1f53700-099b-4653-93f1-6b39acdc4c58¹depends_on_disabled_cells§runtime΢éµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2d8661f1-6f78-4161-a306-982e3ddf3646Цqueued¤logs�§running¦output†¤body ¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ­†4yÿ°persist_js_state·has_pluto_hook_features§cell_idÙ$2d8661f1-6f78-4161-a306-982e3ddf3646¹depends_on_disabled_cells§runtimeÎ@•µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$db24490e-7eac-11ea-094e-9d3fc8f22784Цqueued¤logs�§running¦output†¤bodyÚD

Bound variables

A basic interactive cell looks like this: we use the @bind macro, define a Julia variable, and add a bit of HTML code that creates an <input> element. The HTML element will be rendered as the cell's output.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0@¼°persist_js_state·has_pluto_hook_features§cell_idÙ$db24490e-7eac-11ea-094e-9d3fc8f22784¹depends_on_disabled_cells§runtimeÎ Cµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$901c2b84-14b8-4deb-89d6-705a4972582cЦqueued¤logs�§running¦output†¤body§missing¤mimeªtext/plain¬rootassigneeÀ²last_run_timestampËAÚ­†3ú<Ͱpersist_js_state·has_pluto_hook_features§cell_idÙ$901c2b84-14b8-4deb-89d6-705a4972582c¹depends_on_disabled_cells§runtimeÍJˆµpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$2714a923-2be5-4cf9-97dd-75347968dfeeЦqueued¤logs�§running¦output†¤body¡5¤mimeªtext/plain¬rootassignee¥limit²last_run_timestampËAÚ­†3ð#£°persist_js_state·has_pluto_hook_features§cell_idÙ$2714a923-2be5-4cf9-97dd-75347968dfee¹depends_on_disabled_cells§runtimeÍ"µpublished_object_keys�¸depends_on_skipped_cells§erroredÂÙ$863c5996-9892-4bfc-96ba-225fa4a2266cЦqueued¤logs�§running¦output†¤bodyÚO

Tip

To avoid confusing your readers, it's a good idea to put a ; at the end of the cell where you define the interactive element, like we did here. This way, we only show sliders that are actually bound to something.

¤mime©text/html¬rootassigneeÀ²last_run_timestampËAÚ­†0þ.°persist_js_state·has_pluto_hook_features§cell_idÙ$863c5996-9892-4bfc-96ba-225fa4a2266c¹depends_on_disabled_cells§runtimeÎîCµpublished_object_keys�¸depends_on_skipped_cells§errored±cell_dependenciesÞ0Ù$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2„´precedence_heuristic §cell_idÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$beb9a2bd-cbf5-4679-8403-fc249191f65e„´precedence_heuristic §cell_idÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$7b11caf2-1fc1-4e34-8b97-eab86e3557db„´precedence_heuristic §cell_idÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f„´precedence_heuristic §cell_idÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$33b5374c-91d1-4122-82c5-f793d063ffdc„´precedence_heuristic §cell_idÙ$33b5374c-91d1-4122-82c5-f793d063ffdc´downstream_cells_map�¡b‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$4a235d55-a80f-43c7-8f13-759976d88656„´precedence_heuristic §cell_idÙ$4a235d55-a80f-43c7-8f13-759976d88656´downstream_cells_map�¡a‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$788c0b9b-238f-4402-b24f-52648103512e„´precedence_heuristic §cell_idÙ$788c0b9b-238f-4402-b24f-52648103512e´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$2969d603-9b6c-403e-abdc-af078c2e53f1„´precedence_heuristic §cell_idÙ$2969d603-9b6c-403e-abdc-af078c2e53f1´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6e„´precedence_heuristic §cell_idÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e´downstream_cells_map€²upstream_cells_map�§limited‘Ù$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$73c8532e-09a6-429b-b8f6-530c00d92428„´precedence_heuristic §cell_idÙ$73c8532e-09a6-429b-b8f6-530c00d92428´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$1ebba747-47f8-4ecd-809d-359e6d803ddc„´precedence_heuristic §cell_idÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc´downstream_cells_map�¡y�²upstream_cells_map‚¡^�¡x‘Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac„´precedence_heuristic §cell_idÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$de1b9643-66fa-4918-9a93-0f340c8548ba„´precedence_heuristic §cell_idÙ$de1b9643-66fa-4918-9a93-0f340c8548ba´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$82c7b1ea-08c0-495f-baba-37e5497abde2„´precedence_heuristic §cell_idÙ$82c7b1ea-08c0-495f-baba-37e5497abde2´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$cb65a4ee-02e5-4779-8728-b994d8af645d„´precedence_heuristic §cell_idÙ$cb65a4ee-02e5-4779-8728-b994d8af645d´downstream_cells_map€²upstream_cells_map‚¦typeof�¡x‘Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013„´precedence_heuristic §cell_idÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013´downstream_cells_map�¯limited_counter‘Ù$901c2b84-14b8-4deb-89d6-705a4972582c²upstream_cells_map‰¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¤HTML�¯Core.applicable�¨Base.get�¥@bind�¥limit‘Ù$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d„´precedence_heuristic §cell_idÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d´downstream_cells_map�¡e‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$ced18648-7eb2-11ea-2052-07795685f0da„´precedence_heuristic §cell_idÙ$ced18648-7eb2-11ea-2052-07795685f0da´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$e2854aa0-e3c5-423d-80d9-fc875c5dd54d„´precedence_heuristic §cell_idÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$bd24d02c-7eac-11ea-14ab-95021678e71e„´precedence_heuristic §cell_idÙ$bd24d02c-7eac-11ea-14ab-95021678e71e´downstream_cells_map�¡x“Ù$cb1fd532-7eac-11ea-307c-ab16b1977819Ù$cb65a4ee-02e5-4779-8728-b994d8af645dÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$0a7018ca-2afe-42b1-850f-a649e570709f„´precedence_heuristic §cell_idÙ$0a7018ca-2afe-42b1-850f-a649e570709f´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$5301eb68-7f14-11ea-3ff6-1f075bf73955„´precedence_heuristic §cell_idÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$f595bdb6-bd15-4c62-9de6-49f14c7d365a„´precedence_heuristic §cell_idÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a´downstream_cells_map�¡f‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$d5b3adc5-2c99-4901-adf5-8d8579a32b51„´precedence_heuristic §cell_idÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$c50a5e52-7c95-445c-86ee-c60104a39dbd„´precedence_heuristic §cell_idÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$3b6dc6d5-ce96-40f6-97f7-511ea6d49122„´precedence_heuristic §cell_idÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122´downstream_cells_map�¢x2‘Ù$3297233b-9567-4d5e-8138-93ebe20fed48²upstream_cells_mapˆ¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¯Core.applicable�¨myslider‘Ù$2d8661f1-6f78-4161-a306-982e3ddf3646¥@bind�¨Base.get�Ù$5bd8b261-a89d-46a3-bb59-c95a1801c881„´precedence_heuristic §cell_idÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881´downstream_cells_map€²upstream_cells_map�§counter‘Ù$e3eb31ae-c512-426f-915c-01144edbc90dÙ$e3eb31ae-c512-426f-915c-01144edbc90d„´precedence_heuristic §cell_idÙ$e3eb31ae-c512-426f-915c-01144edbc90d´downstream_cells_map�§counter‘Ù$5bd8b261-a89d-46a3-bb59-c95a1801c881²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$2cefd0de-db13-49c1-abeb-097792ef46f6„´precedence_heuristic §cell_idÙ$2cefd0de-db13-49c1-abeb-097792ef46f6´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$3297233b-9567-4d5e-8138-93ebe20fed48„´precedence_heuristic §cell_idÙ$3297233b-9567-4d5e-8138-93ebe20fed48´downstream_cells_map€²upstream_cells_map‚¢x1‘Ù$c5a5e243-39d6-43d9-8de7-887661ba99cd¢x2‘Ù$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Ù$cb1fd532-7eac-11ea-307c-ab16b1977819„´precedence_heuristic §cell_idÙ$cb1fd532-7eac-11ea-307c-ab16b1977819´downstream_cells_map€²upstream_cells_map�¡x‘Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$9985a640-c1d3-48dc-b00b-d7500085a37b„´precedence_heuristic §cell_idÙ$9985a640-c1d3-48dc-b00b-d7500085a37b´downstream_cells_map�¡d‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$816ea402-7eae-11ea-2134-fb595cca3068„´precedence_heuristic §cell_idÙ$816ea402-7eae-11ea-2134-fb595cca3068´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$d38d06f2-90ce-4e5a-9218-f5a52812e4a2„´precedence_heuristic §cell_idÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2´downstream_cells_map�¡c‘Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf²upstream_cells_mapˆ¤Base�´PlutoRunner.Base.get�©@html_str�Ù#PlutoRunner.PlutoRunner.create_bond�«PlutoRunner�®Base.Docs.HTML�¥@bind�»PlutoRunner.Core.applicable�Ù$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf„´precedence_heuristic §cell_idÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$1a338f77-d8f3-4569-a2d5-c174368a4761„´precedence_heuristic §cell_idÙ$1a338f77-d8f3-4569-a2d5-c174368a4761´downstream_cells_map�§limited‘Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6e²upstream_cells_map‰¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¤HTML�¯Core.applicable�¨Base.get�¥@bind�¥limit‘Ù$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd„´precedence_heuristic §cell_idÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd´downstream_cells_map�¢x1‘Ù$3297233b-9567-4d5e-8138-93ebe20fed48²upstream_cells_mapˆ¤Core�¤Base�·PlutoRunner.create_bond�«PlutoRunner�¯Core.applicable�¨myslider‘Ù$2d8661f1-6f78-4161-a306-982e3ddf3646¥@bind�¨Base.get�Ù$ff3abf71-cff6-459d-a622-0ec0ca8f164b„´precedence_heuristic §cell_idÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$bb4b557b-e4fc-45f3-9d1f-060198167bfa„´precedence_heuristic §cell_idÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$8f829274-7eb1-11ea-3888-13c00b3ba70f„´precedence_heuristic §cell_idÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$ede8009e-7f15-11ea-192a-a5c6135a9dcf„´precedence_heuristic §cell_idÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf´downstream_cells_map€²upstream_cells_map†¡f‘Ù$f595bdb6-bd15-4c62-9de6-49f14c7d365a¡c‘Ù$d38d06f2-90ce-4e5a-9218-f5a52812e4a2¡e‘Ù$b6501bfb-5e1d-40b9-bd16-d38085d2611d¡b‘Ù$33b5374c-91d1-4122-82c5-f793d063ffdc¡a‘Ù$4a235d55-a80f-43c7-8f13-759976d88656¡d‘Ù$9985a640-c1d3-48dc-b00b-d7500085a37bÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403„´precedence_heuristic §cell_idÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$f1f53700-099b-4653-93f1-6b39acdc4c58„´precedence_heuristic §cell_idÙ$f1f53700-099b-4653-93f1-6b39acdc4c58´downstream_cells_map€²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$2d8661f1-6f78-4161-a306-982e3ddf3646„´precedence_heuristic §cell_idÙ$2d8661f1-6f78-4161-a306-982e3ddf3646´downstream_cells_map�¨myslider’Ù$c5a5e243-39d6-43d9-8de7-887661ba99cdÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122²upstream_cells_mapƒ¤Base�®Base.Docs.HTML�©@html_str�Ù$db24490e-7eac-11ea-094e-9d3fc8f22784„´precedence_heuristic §cell_idÙ$db24490e-7eac-11ea-094e-9d3fc8f22784´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�Ù$901c2b84-14b8-4deb-89d6-705a4972582c„´precedence_heuristic §cell_idÙ$901c2b84-14b8-4deb-89d6-705a4972582c´downstream_cells_map€²upstream_cells_map�¯limited_counter‘Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013Ù$2714a923-2be5-4cf9-97dd-75347968dfee„´precedence_heuristic §cell_idÙ$2714a923-2be5-4cf9-97dd-75347968dfee´downstream_cells_map�¥limit’Ù$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013²upstream_cells_map€Ù$863c5996-9892-4bfc-96ba-225fa4a2266c„´precedence_heuristic §cell_idÙ$863c5996-9892-4bfc-96ba-225fa4a2266c´downstream_cells_map€²upstream_cells_map‚§@md_str�¨getindex�´cell_execution_orderÜ0Ù$73c8532e-09a6-429b-b8f6-530c00d92428Ù$db24490e-7eac-11ea-094e-9d3fc8f22784Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2Ù$cb1fd532-7eac-11ea-307c-ab16b1977819Ù$0a7018ca-2afe-42b1-850f-a649e570709fÙ$cb65a4ee-02e5-4779-8728-b994d8af645dÙ$816ea402-7eae-11ea-2134-fb595cca3068Ù$1ebba747-47f8-4ecd-809d-359e6d803ddcÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955Ù$4a235d55-a80f-43c7-8f13-759976d88656Ù$33b5374c-91d1-4122-82c5-f793d063ffdcÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2Ù$9985a640-c1d3-48dc-b00b-d7500085a37bÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611dÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365aÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcfÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403Ù$2969d603-9b6c-403e-abdc-af078c2e53f1Ù$de1b9643-66fa-4918-9a93-0f340c8548baÙ$f1f53700-099b-4653-93f1-6b39acdc4c58Ù$cf9d49cc-fc70-480c-9f6b-850b0ba4c01fÙ$beb9a2bd-cbf5-4679-8403-fc249191f65eÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecfÙ$e3eb31ae-c512-426f-915c-01144edbc90dÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881Ù$7b11caf2-1fc1-4e34-8b97-eab86e3557dbÙ$c50a5e52-7c95-445c-86ee-c60104a39dbdÙ$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6eÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54dÙ$2cefd0de-db13-49c1-abeb-097792ef46f6Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013Ù$901c2b84-14b8-4deb-89d6-705a4972582cÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51Ù$788c0b9b-238f-4402-b24f-52648103512eÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfaÙ$2d8661f1-6f78-4161-a306-982e3ddf3646Ù$c5a5e243-39d6-43d9-8de7-887661ba99cdÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Ù$3297233b-9567-4d5e-8138-93ebe20fed48Ù$82c7b1ea-08c0-495f-baba-37e5497abde2Ù$863c5996-9892-4bfc-96ba-225fa4a2266cÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164bÙ$582769e6-7eb1-11ea-077d-d9b4a3226aacÙ$8f829274-7eb1-11ea-3888-13c00b3ba70fÙ$ced18648-7eb2-11ea-2052-07795685f0da´last_hot_reload_timeË©shortpathºInteractivity with HTML.jl®process_status¥ready¤pathÙQ/home/fons/featured-slider-server/featured_fix/src/web/Interactivity with HTML.jl­pluto_version¦v1.0.0®last_save_timeËAÚ­†0pªcell_orderÜ0Ù$73c8532e-09a6-429b-b8f6-530c00d92428Ù$db24490e-7eac-11ea-094e-9d3fc8f22784Ù$bd24d02c-7eac-11ea-14ab-95021678e71eÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2Ù$cb1fd532-7eac-11ea-307c-ab16b1977819Ù$0a7018ca-2afe-42b1-850f-a649e570709fÙ$cb65a4ee-02e5-4779-8728-b994d8af645dÙ$816ea402-7eae-11ea-2134-fb595cca3068Ù$1ebba747-47f8-4ecd-809d-359e6d803ddcÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955Ù$4a235d55-a80f-43c7-8f13-759976d88656Ù$33b5374c-91d1-4122-82c5-f793d063ffdcÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2Ù$9985a640-c1d3-48dc-b00b-d7500085a37bÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611dÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365aÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcfÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403Ù$2969d603-9b6c-403e-abdc-af078c2e53f1Ù$de1b9643-66fa-4918-9a93-0f340c8548baÙ$f1f53700-099b-4653-93f1-6b39acdc4c58Ù$cf9d49cc-fc70-480c-9f6b-850b0ba4c01fÙ$beb9a2bd-cbf5-4679-8403-fc249191f65eÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecfÙ$e3eb31ae-c512-426f-915c-01144edbc90dÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881Ù$7b11caf2-1fc1-4e34-8b97-eab86e3557dbÙ$c50a5e52-7c95-445c-86ee-c60104a39dbdÙ$2714a923-2be5-4cf9-97dd-75347968dfeeÙ$1a338f77-d8f3-4569-a2d5-c174368a4761Ù$f39435d3-ed67-45f1-ae56-49cf5ec69d6eÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54dÙ$2cefd0de-db13-49c1-abeb-097792ef46f6Ù$f558f689-bd7a-4c65-8b3d-b3681a4ed013Ù$901c2b84-14b8-4deb-89d6-705a4972582cÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51Ù$788c0b9b-238f-4402-b24f-52648103512eÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfaÙ$2d8661f1-6f78-4161-a306-982e3ddf3646Ù$c5a5e243-39d6-43d9-8de7-887661ba99cdÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122Ù$3297233b-9567-4d5e-8138-93ebe20fed48Ù$82c7b1ea-08c0-495f-baba-37e5497abde2Ù$863c5996-9892-4bfc-96ba-225fa4a2266cÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164bÙ$582769e6-7eb1-11ea-077d-d9b4a3226aacÙ$8f829274-7eb1-11ea-3888-13c00b3ba70fÙ$ced18648-7eb2-11ea-2052-07795685f0da­julia_version§v1.12.4±published_objects€¥nbpkgНinstall_time_nsÎ8R}L¬instantiatedòinstalled_versions‚Ù!__internal_julia_manifest_version¦1.12.4¸__internal_julia_version¦1.12.4°terminal_outputs�ªnbpkg_syncÚ Waiting for the package registry to update... === Resolving... ===  Project No packages added to or removed from `~/.julia/scratchspaces/c3e4b0f8-55cb-11ea-2926-15256bba5781/pkg_envs/env_bfhpkzpcbx/Project.toml`  Manifest No packages added to or removed from `~/.julia/scratchspaces/c3e4b0f8-55cb-11ea-2926-15256bba5781/pkg_envs/env_bfhpkzpcbx/Manifest.toml` Instantiating... === Precompiling... ===§enabled÷restart_recommended_msgÀ´restart_required_msgÀ­busy_packages�¶waiting_for_permissionÂÙ,waiting_for_permission_but_probably_disabled«cell_inputsÞ0Ù$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2„§cell_idÙ$cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2¤codeÙ‹md""" That's all you need! Pluto will synchronise the value of `x` with the latest value of the HTML input. Try moving the slider! 👆 """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e„§cell_idÙ$beb9a2bd-cbf5-4679-8403-fc249191f65e¤codeÚ«html"""
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db„§cell_idÙ$7b11caf2-1fc1-4e34-8b97-eab86e3557db¤codeÚTmd""" !!! tip In this example, we immediately call `update()` and trigger an input event with the initial value. If we didn't do that, the value of `counter` would be `nothing` until the first interaction. Whether that's appropriate, depends on the interaction you want. In this case, it made sense that the counter should start at 0! """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f„§cell_idÙ$cf9d49cc-fc70-480c-9f6b-850b0ba4c01f¤codeÙümd""" The script is now keeping track of clicks, but it's not sending that value anywhere. We need to: - Update the parent's element `value` property (this is what Pluto will be reading). - Dispatch an `"input"` event to trigger change detection. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$33b5374c-91d1-4122-82c5-f793d063ffdc„§cell_idÙ$33b5374c-91d1-4122-82c5-f793d063ffdc¤codeÙ @bind b html""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$4a235d55-a80f-43c7-8f13-759976d88656„§cell_idÙ$4a235d55-a80f-43c7-8f13-759976d88656¤codeÙ!@bind a html""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$788c0b9b-238f-4402-b24f-52648103512e„§cell_idÙ$788c0b9b-238f-4402-b24f-52648103512e¤codeÙÃmd""" If you're looking for something more sophisticated than simple string interpolation, check out the [HyperTextLiteral package](https://juliapluto.github.io/HypertextLiteral.jl/stable/)! """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$2969d603-9b6c-403e-abdc-af078c2e53f1„§cell_idÙ$2969d603-9b6c-403e-abdc-af078c2e53f1¤codeÙ‚html"""
Let's make something interactive here!
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e„§cell_idÙ$f39435d3-ed67-45f1-ae56-49cf5ec69d6e¤code§limited¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$73c8532e-09a6-429b-b8f6-530c00d92428„§cell_idÙ$73c8532e-09a6-429b-b8f6-530c00d92428¤codeÚ[md""" # Interactivity with HTML Pluto notebooks can use the `@bind` macro for interactive inputs. Neat! If you're completely new to coding anything interactive in a web browser, the easiest way to get started is with the `PlutoUI` package in Julia. (Check out the [PlutoUI featured notebook](https://featured.plutojl.org/basic/plutoui.jl) if you'd like to learn more about that!) If you have some experience with HTML, or if you would like to learn how to make your own interactive elements, this notebook is for you! We'll cover the basics of using `@bind` with HTML elements. Let's get started! """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc„§cell_idÙ$1ebba747-47f8-4ecd-809d-359e6d803ddc¤code§y = x^2¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac„§cell_idÙ$582769e6-7eb1-11ea-077d-d9b4a3226aac¤codeÚvmd""" ## Behind the scenes If you're curious to learn a bit more about how this all works, keep reading! ### The output value As we've mentioned, bound values are just the latest value of the input element, rather than some kind of observable. The update mechanism is _lossy_ and _lazy_, which means that it will skip values if your code is still running - and **only send the latest value when your code is ready again**. This is important when changing a slider from `0` to `100`, for example. If it would send all intermediate values, it might take a while for your code to process everything, causing a noticeable lag. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$de1b9643-66fa-4918-9a93-0f340c8548ba„§cell_idÙ$de1b9643-66fa-4918-9a93-0f340c8548ba¤codeÙ”md""" Now we can use the script to handle whatever interaction we want. For a simple element, let's add a button and count the number of clicks. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$82c7b1ea-08c0-495f-baba-37e5497abde2„§cell_idÙ$82c7b1ea-08c0-495f-baba-37e5497abde2¤codeÙ!md""" It's as simple as that! """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$cb65a4ee-02e5-4779-8728-b994d8af645d„§cell_idÙ$cb65a4ee-02e5-4779-8728-b994d8af645d¤code©typeof(x)¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013„§cell_idÙ$f558f689-bd7a-4c65-8b3d-b3681a4ed013¤codeÚø@bind limited_counter HTML("""
""")¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d„§cell_idÙ$b6501bfb-5e1d-40b9-bd16-d38085d2611d¤codeÙ!@bind e html""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$ced18648-7eb2-11ea-2052-07795685f0da„§cell_idÙ$ced18648-7eb2-11ea-2052-07795685f0da¤codeÚamd"#### JavaScript? Yes! We are using `Generator.input` from [`observablehq/stdlib`](https://github.com/observablehq/stdlib#Generators_input) to create a JS _Generator_ (kind of like an Observable) that listens to `onchange`, `onclick` or `oninput` events, [depending on the element type](https://github.com/observablehq/stdlib#Generators_input). This makes it super easy to create nice HTML/JS-based interaction elements - a package creator simply has to write a `show` method for MIME type `text/html` that creates a DOM object that triggers the `input` event. In other words, _Pluto's `@bind` will behave exactly like [`viewof` in observablehq](https://observablehq.com/@observablehq/introduction-to-views)_. _If you want to learn more about using Javascript in Pluto, check out the [JavaScript sample notebook](https://featured.plutojl.org/web/javascript)!_"¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d„§cell_idÙ$e2854aa0-e3c5-423d-80d9-fc875c5dd54d¤codeÙwmd""" Keep in mind that changing the value of `limit` will re-evaluate the slider cell, so it will reset the value. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$bd24d02c-7eac-11ea-14ab-95021678e71e„§cell_idÙ$bd24d02c-7eac-11ea-14ab-95021678e71e¤codeÙ @bind x html""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$0a7018ca-2afe-42b1-850f-a649e570709f„§cell_idÙ$0a7018ca-2afe-42b1-850f-a649e570709f¤codeÙfmd""" A neat aspect of this `@bind` macro is that on the Julia side, `x` is just a normal integer: """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955„§cell_idÙ$5301eb68-7f14-11ea-3ff6-1f075bf73955¤codeÙ¯md""" ## Input types You can use binds with anything that fires an [`input` event](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event). For example: """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a„§cell_idÙ$f595bdb6-bd15-4c62-9de6-49f14c7d365a¤code¿@bind f html""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51„§cell_idÙ$d5b3adc5-2c99-4901-adf5-8d8579a32b51¤codeÚ6md""" !!! tip Interpolating values in Javascript is neat, but remember that we are just taking the string representation of the variable and pasting it in the javascript code. For some complex data types like dates, you will need to do a bit of conversion to turn them into proper javascript expressions. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd„§cell_idÙ$c50a5e52-7c95-445c-86ee-c60104a39dbd¤codeÚtmd""" ## Using Julia values in HTML We've seen how you can pass on values from an interactive HTML element on to Julia, but for proper interaction, we also want to do it the other way around! The most basic way to do this is string interpolation. In this example, you can change the value of `limit` in the code to affect the maximum value of the slider. Try it out! """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122„§cell_idÙ$3b6dc6d5-ce96-40f6-97f7-511ea6d49122¤code±@bind x2 myslider¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881„§cell_idÙ$5bd8b261-a89d-46a3-bb59-c95a1801c881¤code§counter¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$e3eb31ae-c512-426f-915c-01144edbc90d„§cell_idÙ$e3eb31ae-c512-426f-915c-01144edbc90d¤codeÚ¹@bind counter html"""
"""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$2cefd0de-db13-49c1-abeb-097792ef46f6„§cell_idÙ$2cefd0de-db13-49c1-abeb-097792ef46f6¤codeÙŸmd""" For something even fancier, you can also interpolate value in Javascript. For example, here I have adapted my counter so it won't count past `limit`: """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$3297233b-9567-4d5e-8138-93ebe20fed48„§cell_idÙ$3297233b-9567-4d5e-8138-93ebe20fed48¤code¦x1, x2¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$cb1fd532-7eac-11ea-307c-ab16b1977819„§cell_idÙ$cb1fd532-7eac-11ea-307c-ab16b1977819¤code¡x¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$9985a640-c1d3-48dc-b00b-d7500085a37b„§cell_idÙ$9985a640-c1d3-48dc-b00b-d7500085a37b¤codeÙo@bind d html""" """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$816ea402-7eae-11ea-2134-fb595cca3068„§cell_idÙ$816ea402-7eae-11ea-2134-fb595cca3068¤codeÙæmd""" Not an observable, callback, or something else that you need to wrap your head around. You can use `x` like you would any other number, and Pluto's reactivity means anything depending on `x` will be updated with it. 🚀 """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2„§cell_idÙ$d38d06f2-90ce-4e5a-9218-f5a52812e4a2¤codeÙ$@bind c html""¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf„§cell_idÙ$6b9a590b-ce24-4a9a-b5b4-5b353e6ccecf¤codeÙYmd""" Okay, now we can use this HTML snippet with a `@bind` macro and see the result! """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$1a338f77-d8f3-4569-a2d5-c174368a4761„§cell_idÙ$1a338f77-d8f3-4569-a2d5-c174368a4761¤codeÙH@bind limited HTML(""" """)¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd„§cell_idÙ$c5a5e243-39d6-43d9-8de7-887661ba99cd¤code±@bind x1 myslider¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b„§cell_idÙ$ff3abf71-cff6-459d-a622-0ec0ca8f164b¤codeÚ+md""" This is is how the `PlutoUI` package works - it defines HTML literals - sometimes with their own scripts. If you've written some cool HTML inputs and you want to share them with others, you can also make a UI package! Just publish those definitions as a Julia package and you're done! ✨ """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa„§cell_idÙ$bb4b557b-e4fc-45f3-9d1f-060198167bfa¤codeÙ»md""" ## Reusing elements Once you've written some neat interactive element, you may want to use it a few times in notebook. The easiest way is to put the HTML literal in a variable. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f„§cell_idÙ$8f829274-7eb1-11ea-3888-13c00b3ba70f¤codeÚ�md"""### What does the macro do? The `@bind` macro does not actually contain the interactivity mechanism, this is built into Pluto itself. Still, it does two things: it assigns a _default value_ to the variable (`missing` in most cases), and it wraps the second argument in a `PlutoRunner.Bond` object. For example, _expanding_ the `@bind` macro turns this expression: ```julia @bind x Slider(5:15) ``` into (simplified): ```julia begin local el = Slider(5:15) global x = AbstractPlutoDingetjes.intial_value(el) PlutoRunner.create_bond(el, :x) end ``` We see that the macro creates a variable `x`, which is given the value `AbstractPlutoDingetjes.intial_value(el)`. This function returns `missing` by default, unless a method was implemented for your widget type. For example, `PlutoUI` has a `Slider` type, and it defines a method for `intial_value(slider::Slider)` that returns the default number. Declaring a default value using `AbstractPlutoDingetjes` is **not necessary**, as shown by the earlier examples in this notebook, but the default value will be used for `x` if the `notebook.jl` file is _run as a plain julia file_, without Pluto's interactivity. You don't need to worry about this if you are just getting started with Pluto and interactive elements, but more advanced users should take a look at [`AbstractPlutoDingetjes.jl`](https://github.com/JuliaPluto/AbstractPlutoDingetjes.jl). """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf„§cell_idÙ$ede8009e-7f15-11ea-192a-a5c6135a9dcf¤code²(a, b, c, d, e, f)¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403„§cell_idÙ$c1b9fbbb-3629-4abf-b11a-b7345b01d403¤codeÚ‹md""" ## Scripting inputs with Javascript You can also use Javascript to write more complicated inputs. To get started with this, add a ` """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$2d8661f1-6f78-4161-a306-982e3ddf3646„§cell_idÙ$2d8661f1-6f78-4161-a306-982e3ddf3646¤codeÙTmyslider = html"""""";¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$db24490e-7eac-11ea-094e-9d3fc8f22784„§cell_idÙ$db24490e-7eac-11ea-094e-9d3fc8f22784¤codeÙðmd""" ## Bound variables A basic interactive cell looks like this: we use the `@bind` macro, define a Julia variable, and add a bit of HTML code that creates an `` element. The HTML element will be rendered as the cell's output. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÃÙ$901c2b84-14b8-4deb-89d6-705a4972582c„§cell_idÙ$901c2b84-14b8-4deb-89d6-705a4972582c¤code¯limited_counter¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$2714a923-2be5-4cf9-97dd-75347968dfee„§cell_idÙ$2714a923-2be5-4cf9-97dd-75347968dfee¤code©limit = 5¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedÂÙ$863c5996-9892-4bfc-96ba-225fa4a2266c„§cell_idÙ$863c5996-9892-4bfc-96ba-225fa4a2266c¤codeÙêmd""" !!! tip To avoid confusing your readers, it's a good idea to put a `;` at the end of the cell where you define the interactive element, like we did here. This way, we only show sliders that are actually bound to something. """¨metadataƒ©show_logsèdisabled®skip_as_script«code_foldedënotebook_idÙ$c3bafdee-b8ac-11f1-a96d-ff72b023af58«in_temp_dir¨metadata�«frontmatterˆ«license_urlÙghttps://github.com/JuliaPluto/featured/blob/2a6a9664e5428b37abe4957c1dca0994f4a8b7fd/LICENSES/Unlicense¦author‘‚¤name¨Pluto.jl£url½https://github.com/JuliaPluto¥imageÙdhttps://user-images.githubusercontent.com/6933510/174067982-904951c4-4bba-42c7-a340-102ceb7e8e10.png¥order¡1¥title·Interactivity with HTML¤tags“­interactivity§classic£web§license©Unlicense«descriptionÙ.Write your own interactive controls with HTML!